Commit 55851f73 authored by Clemens Ladisch's avatar Clemens Ladisch Committed by Jaroslav Kysela

[ALSA] usb-audio: use usb_buffer_alloc/free

USB generic driver
Use the USB buffer allocation functions to avoid repeated DMA mappings
of our buffers, which are re-used quite a lot.
Signed-off-by: default avatarClemens Ladisch <clemens@ladisch.de>
parent daa150ef
...@@ -127,6 +127,7 @@ struct audioformat { ...@@ -127,6 +127,7 @@ struct audioformat {
struct snd_urb_ctx { struct snd_urb_ctx {
struct urb *urb; struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
snd_usb_substream_t *subs; snd_usb_substream_t *subs;
int index; /* index for urb array */ int index; /* index for urb array */
int packets; /* number of packets per urb */ int packets; /* number of packets per urb */
...@@ -176,7 +177,8 @@ struct snd_usb_substream { ...@@ -176,7 +177,8 @@ struct snd_usb_substream {
unsigned int nurbs; /* # urbs */ unsigned int nurbs; /* # urbs */
snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */
snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */
char syncbuf[SYNC_URBS * 4]; /* sync buffer; it's so small - let's get static */ char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */
u64 formats; /* format bitmasks (all or'ed) */ u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */ unsigned int num_formats; /* number of supported audio formats (list) */
...@@ -855,7 +857,10 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -855,7 +857,10 @@ static int snd_usb_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
static void release_urb_ctx(snd_urb_ctx_t *u) static void release_urb_ctx(snd_urb_ctx_t *u)
{ {
if (u->urb) { if (u->urb) {
kfree(u->urb->transfer_buffer); if (u->buffer_size)
usb_buffer_free(u->subs->dev, u->buffer_size,
u->urb->transfer_buffer,
u->urb->transfer_dma);
usb_free_urb(u->urb); usb_free_urb(u->urb);
u->urb = NULL; u->urb = NULL;
} }
...@@ -876,6 +881,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force) ...@@ -876,6 +881,9 @@ static void release_substream_urbs(snd_usb_substream_t *subs, int force)
release_urb_ctx(&subs->dataurb[i]); release_urb_ctx(&subs->dataurb[i]);
for (i = 0; i < SYNC_URBS; i++) for (i = 0; i < SYNC_URBS; i++)
release_urb_ctx(&subs->syncurb[i]); release_urb_ctx(&subs->syncurb[i]);
usb_buffer_free(subs->dev, SYNC_URBS * 4,
subs->syncbuf, subs->sync_dma);
subs->syncbuf = NULL;
subs->nurbs = 0; subs->nurbs = 0;
} }
...@@ -986,21 +994,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -986,21 +994,19 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
u->index = i; u->index = i;
u->subs = subs; u->subs = subs;
u->packets = npacks[i]; u->packets = npacks[i];
u->buffer_size = maxsize * u->packets;
if (subs->fmt_type == USB_FORMAT_TYPE_II) if (subs->fmt_type == USB_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */ u->packets++; /* for transfer delimiter */
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
if (! u->urb) { if (! u->urb)
release_substream_urbs(subs, 0); goto out_of_memory;
return -ENOMEM; u->urb->transfer_buffer =
} usb_buffer_alloc(subs->dev, u->buffer_size, GFP_KERNEL,
u->urb->transfer_buffer = kmalloc(maxsize * u->packets, &u->urb->transfer_dma);
GFP_KERNEL); if (! u->urb->transfer_buffer)
if (! u->urb->transfer_buffer) { goto out_of_memory;
release_substream_urbs(subs, 0);
return -ENOMEM;
}
u->urb->pipe = subs->datapipe; u->urb->pipe = subs->datapipe;
u->urb->transfer_flags = URB_ISO_ASAP; u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
u->urb->interval = 1 << subs->datainterval; u->urb->interval = 1 << subs->datainterval;
u->urb->context = u; u->urb->context = u;
u->urb->complete = snd_usb_complete_callback(snd_complete_urb); u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
...@@ -1008,20 +1014,24 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -1008,20 +1014,24 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
if (subs->syncpipe) { if (subs->syncpipe) {
/* allocate and initialize sync urbs */ /* allocate and initialize sync urbs */
subs->syncbuf = usb_buffer_alloc(subs->dev, SYNC_URBS * 4,
GFP_KERNEL, &subs->sync_dma);
if (! subs->syncbuf)
goto out_of_memory;
for (i = 0; i < SYNC_URBS; i++) { for (i = 0; i < SYNC_URBS; i++) {
snd_urb_ctx_t *u = &subs->syncurb[i]; snd_urb_ctx_t *u = &subs->syncurb[i];
u->index = i; u->index = i;
u->subs = subs; u->subs = subs;
u->packets = 1; u->packets = 1;
u->urb = usb_alloc_urb(1, GFP_KERNEL); u->urb = usb_alloc_urb(1, GFP_KERNEL);
if (! u->urb) { if (! u->urb)
release_substream_urbs(subs, 0); goto out_of_memory;
return -ENOMEM;
}
u->urb->transfer_buffer = subs->syncbuf + i * 4; u->urb->transfer_buffer = subs->syncbuf + i * 4;
u->urb->transfer_dma = subs->sync_dma + i * 4;
u->urb->transfer_buffer_length = 4; u->urb->transfer_buffer_length = 4;
u->urb->pipe = subs->syncpipe; u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = URB_ISO_ASAP; u->urb->transfer_flags = URB_ISO_ASAP |
URB_NO_TRANSFER_DMA_MAP;
u->urb->number_of_packets = 1; u->urb->number_of_packets = 1;
u->urb->interval = 1 << subs->syncinterval; u->urb->interval = 1 << subs->syncinterval;
u->urb->context = u; u->urb->context = u;
...@@ -1029,6 +1039,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by ...@@ -1029,6 +1039,10 @@ static int init_substream_urbs(snd_usb_substream_t *subs, unsigned int period_by
} }
} }
return 0; return 0;
out_of_memory:
release_substream_urbs(subs, 0);
return -ENOMEM;
} }
...@@ -2036,7 +2050,7 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat ...@@ -2036,7 +2050,7 @@ static void init_substream(snd_usb_stream_t *as, int stream, struct audioformat
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, snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream,
SNDRV_DMA_TYPE_CONTINUOUS, SNDRV_DMA_TYPE_CONTINUOUS,
snd_dma_continuous_data(GFP_KERNEL), snd_dma_continuous_data(GFP_NOIO),
64 * 1024, 128 * 1024); 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 ?
......
...@@ -765,7 +765,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = { ...@@ -765,7 +765,10 @@ static snd_rawmidi_ops_t snd_usbmidi_input_ops = {
static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep) static void snd_usbmidi_in_endpoint_delete(snd_usb_midi_in_endpoint_t* ep)
{ {
if (ep->urb) { if (ep->urb) {
kfree(ep->urb->transfer_buffer); usb_buffer_free(ep->umidi->chip->dev,
ep->urb->transfer_buffer_length,
ep->urb->transfer_buffer,
ep->urb->transfer_dma);
usb_free_urb(ep->urb); usb_free_urb(ep->urb);
} }
kfree(ep); kfree(ep);
...@@ -799,7 +802,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi, ...@@ -799,7 +802,8 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
else else
pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep);
length = usb_maxpacket(umidi->chip->dev, pipe, 0); length = usb_maxpacket(umidi->chip->dev, pipe, 0);
buffer = kmalloc(length, GFP_KERNEL); buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL,
&ep->urb->transfer_dma);
if (!buffer) { if (!buffer) {
snd_usbmidi_in_endpoint_delete(ep); snd_usbmidi_in_endpoint_delete(ep);
return -ENOMEM; return -ENOMEM;
...@@ -812,6 +816,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi, ...@@ -812,6 +816,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length, usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, length,
snd_usb_complete_callback(snd_usbmidi_in_urb_complete), snd_usb_complete_callback(snd_usbmidi_in_urb_complete),
ep); ep);
ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
rep->in = ep; rep->in = ep;
return 0; return 0;
...@@ -835,7 +840,9 @@ static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep) ...@@ -835,7 +840,9 @@ static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
if (ep->tasklet.func) if (ep->tasklet.func)
tasklet_kill(&ep->tasklet); tasklet_kill(&ep->tasklet);
if (ep->urb) { if (ep->urb) {
kfree(ep->urb->transfer_buffer); usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer,
ep->urb->transfer_buffer,
ep->urb->transfer_dma);
usb_free_urb(ep->urb); usb_free_urb(ep->urb);
} }
kfree(ep); kfree(ep);
...@@ -867,7 +874,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi, ...@@ -867,7 +874,8 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
/* we never use interrupt output pipes */ /* we never use interrupt output pipes */
pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1);
buffer = kmalloc(ep->max_transfer, GFP_KERNEL); buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer,
GFP_KERNEL, &ep->urb->transfer_dma);
if (!buffer) { if (!buffer) {
snd_usbmidi_out_endpoint_delete(ep); snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM; return -ENOMEM;
...@@ -875,6 +883,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi, ...@@ -875,6 +883,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi,
usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
ep->max_transfer, ep->max_transfer,
snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep); snd_usb_complete_callback(snd_usbmidi_out_urb_complete), ep);
ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
spin_lock_init(&ep->buffer_lock); spin_lock_init(&ep->buffer_lock);
tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep);
......
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